package com.ant.backstage.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.ant.backstage.dao.FileInfoMapper;
import com.ant.backstage.dao.UserMapper;
import com.ant.backstage.facade.ApiReturn;
import com.ant.backstage.facade.code.ApiReturnCode;
import com.ant.backstage.facade.dto.FileInfoDTO;
import com.ant.backstage.facade.dto.UserDTO;
import com.ant.backstage.facade.enums.UploadFileEnum;
import com.ant.backstage.facade.exception.BackstageBusinessException;
import com.ant.backstage.facade.model.FileInfo;
import com.ant.backstage.facade.model.User;
import com.ant.backstage.facade.request.ExportDataRequest;
import com.ant.backstage.facade.request.FilePageInfoRequest;
import com.ant.backstage.facade.request.UpdateFileStatusRequest;
import com.ant.backstage.facade.request.power.PageUserInfoRequest;
import com.ant.backstage.service.EnumService;
import com.ant.backstage.service.FileInfoService;
import com.ant.backstage.service.FileUploadService;
import com.ant.backstage.utils.file.FileUtils;
import com.ant.backstage.utils.jxls.JxlsBuilder;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import ma.glasnost.orika.MapperFacade;
import org.apache.http.entity.ContentType;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

@Service("fileInfoService")
public class FileInfoServiceImpl implements FileInfoService {

    private static Logger logger = LogManager.getLogger(UserServiceImpl.class);

    @Resource
    FileInfoMapper fileInfoMapper;
    @Resource
    MapperFacade mapperFacade;
    @Resource
    EnumService enumService;
    @Resource
    FileUploadService fileUploadService;
    @Resource
    UserMapper userMapper;

    private String DOWN_TEMPLATE_PATH = "D:\\idea-develop-project\\Project_All\\backstage_ant\\web\\src\\main\\resources\\jxls_templates\\";//模板文件下载地址
    private String DOWN_IMG_PATH = "D:\\idea-develop-project\\Project_All\\backstage_ant\\web\\src\\main\\resources\\jxls_images\\";

    @Override
    public PageInfo selectFilePage(FileInfo fileInfo, int pageNum, int pageSize) {

        List<Integer> fileIds = fileInfoMapper.selectFileByCondition(fileInfo);
        PageInfo<Object> pageInfo = null;
        List<FileInfo> resultList = null;
        if (!fileIds.isEmpty()) {
            //使用pageHelper实现分页查询  注意设置完 pageHelper 以后需要接着查询
            PageHelper.startPage(pageNum, pageSize == -1 ? fileIds.size() : pageSize);
            resultList = fileInfoMapper.selectByIds(fileIds);
            pageInfo = new PageInfo(resultList);
        } else {
            logger.info("分页查询,没有符合条件的信息 user={}", JSONObject.toJSONString(fileInfo));
            return pageInfo;
        }
        List<Object> reutlslist = new ArrayList<>();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        ApiReturn uploadFileEnum = enumService.getEnumList("UploadFileEnum");
        if (!Optional.ofNullable(uploadFileEnum.getData()).isPresent()) {
            logger.info("未查询到枚举值 enum={}", JSONObject.toJSONString(uploadFileEnum));
            throw new BackstageBusinessException(ApiReturnCode.UNKNOWN_ERROR.getMessage(),ApiReturnCode.UNKNOWN_ERROR.getCode());
        }
        Map data = (Map) uploadFileEnum.getData();
        List<UploadFileEnum> enumList = (List) data.get("UploadFileEnum");
        resultList.stream().forEach(item -> {
            FileInfoDTO dto = mapperFacade.map(item, FileInfoDTO.class);
            dto.setFileCreateTime(sdf.format(item.getFileCreateTime()));
            //枚举值
            enumList.stream().forEach(en -> {
                if (en.getCode().equals(item.getFileBusinessType())) {
                    dto.setFileBusinessTypeValue(String.valueOf(en.getDesc()));
                }
            });
            reutlslist.add(dto);
        });
        pageInfo.setList(reutlslist);
        return pageInfo;
    }

    @Override
    public ApiReturn updateFileStatus(UpdateFileStatusRequest updateFileStatusRequest) {
        ApiReturn apiReturn = new ApiReturn();
        fileInfoMapper.updateStatusById(updateFileStatusRequest.getId(), updateFileStatusRequest.getFileStatus());
        apiReturn.setApiReturnCode(ApiReturnCode.SUCCESSFUL);
        return apiReturn;
    }

    @Override
    public ApiReturn exportData(ExportDataRequest exportDataRequest, UserDTO userInfoByToken) throws Exception {
        ApiReturn apiReturn = new ApiReturn();
        Map<String, Object> dataMap = new HashMap<>();

        //根据模板业务类型，处理查询参数
        UploadFileEnum byCode = UploadFileEnum.getByCode(exportDataRequest.getFileBusinessType());
        if (byCode == null) {
            logger.error("枚举值获取异常 exportDataRequest={}", JSONObject.toJSONString(exportDataRequest));
            throw new BackstageBusinessException(ApiReturnCode.HTTP_ERROR.getMessage(), ApiReturnCode.HTTP_ERROR.getCode());
        }
        switch (byCode) {
            case DOWN_FILE_DATA_TEMPLATE:   //文件模板导出数据
                ApiReturn a = this.handleFileTemplateData(exportDataRequest, apiReturn);
                if (a.getCode().equals(ApiReturnCode.SUCCESSFUL.getCode())) {
                    dataMap = (Map<String, Object>) a.getData();
                    //模板导出数据

                } else {
                    apiReturn = a;
                }
                break;
            case DOWN_USER_DATA_TEMPLATE:   //用户模板
                ApiReturn u = this.handleUserTemplateData(exportDataRequest, apiReturn);
                if (u.getCode().equals(ApiReturnCode.SUCCESSFUL.getCode())) {
                    dataMap = (Map<String, Object>) u.getData();
                } else {
                    apiReturn = u;
                }
                break;
        }
        // 查模板信息
        FileInfo fileInfo = fileInfoMapper.selectByPrimaryKey(exportDataRequest.getId());
        if (fileInfo.getFileStatus() != 1) {
            apiReturn.setCode(ApiReturnCode.TEMPLATE_NO_USE_ERROR.getCode());
            apiReturn.setMsg(ApiReturnCode.TEMPLATE_NO_USE_ERROR.getMessage());
            return apiReturn;
        }
        //下载需要的模板 到指定文件夹 本地目录 下载文件地址 文件名称
        FileUtils.downloadToServer(fileInfo.getFileUrl(), DOWN_TEMPLATE_PATH, fileInfo.getFileName() + "." + fileInfo.getFileType());
        String inPath = DOWN_TEMPLATE_PATH + fileInfo.getFileName() + "." + fileInfo.getFileType();
        File file = new File(inPath);
        FileInputStream in = null;
        //判断文件是否存在
        if (file.exists()) {
            in = new FileInputStream(inPath);
        }
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
        String outPath = DOWN_TEMPLATE_PATH + sdf.format(new Date()) + "OutNew_" + fileInfo.getFileName() + "." + fileInfo.getFileType();
        FileOutputStream out = new FileOutputStream(outPath);
        dataMap.put("exportTime", new Date());//导出时间
        dataMap.put("exportUser", userInfoByToken.getUname());//导出时间
        //生成
        JxlsBuilder jxlsBuilder = JxlsBuilder
                .getBuilder(in)
                .out(out)
                .ignoreImageMiss(true)
                .putAll(dataMap)//数据源
                .build();
        logger.info("模板数据导出成功！");
        //上传到gitee指定文件夹 定时删除1天一次job
        File outFile = new File(outPath);
        FileInputStream out_file = new FileInputStream(outFile);

        // 转 MultipartFile
        MultipartFile multipartFile = new MockMultipartFile(sdf.format(new Date()) + "OutNew_" + fileInfo.getFileName() + "." + fileInfo.getFileType(),
                file.getName(),
                ContentType.APPLICATION_OCTET_STREAM.toString(),
                out_file);
        ApiReturn exportTemplateSlx = fileUploadService.giteeUploadFile(multipartFile, "exportTemplateSlx");
        if (!exportTemplateSlx.getCode().equals(ApiReturnCode.SUCCESSFUL.getCode())) {
            //上传失败
            apiReturn.setCode(ApiReturnCode.HTTP_ERROR.getCode());
            apiReturn.setMsg(ApiReturnCode.HTTP_ERROR.getMessage());
            return apiReturn;
        }
        //上传成功删除本地文件
        FileUtils.deleteFile(inPath);
        FileUtils.deleteFile(outPath);
        FileUtils.delAllFile(DOWN_IMG_PATH);
        apiReturn = exportTemplateSlx;
        return apiReturn;
    }

    private ApiReturn handleUserTemplateData(ExportDataRequest exportDataRequest, ApiReturn apiReturn) {
        String parmasJson = exportDataRequest.getParamsJson();
        //json转对象
        PageUserInfoRequest request = JSONObject.parseObject(parmasJson, PageUserInfoRequest.class);
        User user = mapperFacade.map(request, User.class);
        //1. 根据条件筛选出符合条件的id
        List<String> uidList = userMapper.selectbyCondition(user);
        if (!Optional.ofNullable(uidList).isPresent()) {
            apiReturn.setCode(ApiReturnCode.NO_TERM_DATAS.getCode());
            apiReturn.setMsg(ApiReturnCode.NO_TERM_DATAS.getMessage());
            return apiReturn;
        }
        List<User> users = null;
        if (uidList.size() < exportDataRequest.getExportNumber()) {
            //全部导出
            users = userMapper.selectUserByuIds(uidList);
        } else {
            List<String> collect = uidList.stream().distinct()
                    .limit(exportDataRequest.getExportNumber() == 0 ? 100 : exportDataRequest.getExportNumber())
                    .collect(Collectors.toList());
            users = userMapper.selectUserByuIds(collect);
        }
        HashMap<String, Object> resultMap = new HashMap<>();
        resultMap.put("data", users);
        apiReturn.setData(resultMap);
        apiReturn.setApiReturnCode(ApiReturnCode.SUCCESSFUL);
        return apiReturn;
    }

    public ApiReturn handleFileTemplateData(ExportDataRequest exportDataRequest, ApiReturn apiReturn) throws IOException {
        String parmasJson = exportDataRequest.getParamsJson();
        //json转对象
        FilePageInfoRequest request = JSONObject.parseObject(parmasJson, FilePageInfoRequest.class);
        FileInfo fileInfo = mapperFacade.map(request, FileInfo.class);
        //获取导出数据
        List<Integer> fileIds = fileInfoMapper.selectFileByCondition(fileInfo);
        if (!Optional.ofNullable(fileIds).isPresent()) {
            apiReturn.setCode(ApiReturnCode.NO_TERM_DATAS.getCode());
            apiReturn.setMsg(ApiReturnCode.NO_TERM_DATAS.getMessage());
            return apiReturn;
        }
        List<FileInfo> fileInfos = null;
        if (fileIds.size() < exportDataRequest.getExportNumber()) {
            //全部导出
            fileInfos = fileInfoMapper.selectByIds(fileIds);
        } else {
            List<Integer> collect = fileIds.stream().distinct()
                    .limit(exportDataRequest.getExportNumber())
                    .sorted(Comparator.reverseOrder()).collect(Collectors.toList());
            fileInfos = fileInfoMapper.selectByIds(collect);
        }

        //Comparator.reverseOrder() 实现降序和升序
        List<FileInfo> collect = fileInfos.stream().sorted(Comparator.comparing(FileInfo::getId)).collect(Collectors.toList());
        //下载图片到指定文件夹
        //遍历文件地址单线程下载文件 非常耗时
        collect.forEach(f -> {
            if (Optional.ofNullable(f.getFileImg()).isPresent()) {
                FileUtils.downloadToServer(f.getFileImg(), DOWN_IMG_PATH, f.getFileImg().substring(f.getFileImg().lastIndexOf("/") + 1));
                f.setFileImg(DOWN_IMG_PATH + f.getFileImg().substring(f.getFileImg().lastIndexOf("/") + 1));
            }
        });
        // 优化多线程下载资源,一个文件用多个线程下载 动态获取文件 由于使用gitee作为文件服务器，gitee不能多个线程下载同一个文件
        /*
         collect.forEach(f -> {
            if (Optional.ofNullable(f.getFileImg()).isPresent()) {
                MultiThreadDownload mtd = new MultiThreadDownload(f.getFileImg(), DOWN_IMG_PATH + f.getFileImg().substring(f.getFileImg().lastIndexOf("/") + 1), 3);//服务器地址 本地地址 开启3个线程
                f.setFileImg(DOWN_IMG_PATH + f.getFileImg().substring(f.getFileImg().lastIndexOf("/") + 1));
                try {
                    mtd.download();//下载
                } catch (IOException e) {
                    e.printStackTrace();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
         */


        HashMap<String, Object> resultMap = new HashMap<>();
        resultMap.put("data", collect);
        resultMap.put("title", "文件模板上传统计");
        apiReturn.setData(resultMap);
        apiReturn.setApiReturnCode(ApiReturnCode.SUCCESSFUL);
        return apiReturn;
    }

}
